package com.simpletour.qa.gateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.simpletour.qa.gateway.exception.JwtNotExistException;
import com.simpletour.qa.gateway.jwt.ClaimsUtil;
import com.simpletour.qa.gateway.jwt.JwtTokenUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;

/**
 * Jwt 校验过滤器
 * @author zhaohw
 * @date 2018-06-20 17:22
 */
@Component
@Slf4j
public class JwtTokenFilter extends ZuulFilter {

    @Autowired
    private FilterSkipConfig filterSkipConfig;

    @Value("${gate.jwt.header}")
    private String tokenHeader;

    /**
     * 不校验Token的URI header
     */
    public static String NON_CHECK_TOKEN = "non_check_token";

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        String requestUri = request.getRequestURI();
        String method = request.getMethod();
        String authToken = request.getHeader(this.tokenHeader);

        if(authToken == null){
            // 无需校验token的uri
            if (filterSkipConfig.isSkipTokenURIByStartWith(requestUri,method)){
                log.info("non-check request URI : {}  method : {}",requestUri,method);
                ctx.addZuulRequestHeader(NON_CHECK_TOKEN,"true");
                return null;
            }else{
                // token不存在抛出异常 由JwtErrorFilter处理
                throw new JwtNotExistException();
            }
        }
        //只要请求带Token 则进行解析
        else{
            /*
             * 获取载荷已经完成了jwt结构、是否失效等基本校验
             * 校验不通过抛出异常 由JwtErrorFilter处理
             */
            Claims claims = JwtTokenUtil.getClaimsFromToken(authToken);
            log.debug(claims.toString());
            ctx = jwtToZuulHeader(claims,ctx);
        }

        log.info("check JWT  for request URI : {}  method : {}",requestUri,method);

        return null;
    }

    /**
     *  JWT载荷转换为Zuul Header
     * @param claims
     * @param context
     * @return
     */
    private RequestContext jwtToZuulHeader(Claims claims , RequestContext context){
        Object userId = claims.get(ClaimsUtil.CLAIM_KEY_USER_ID);
        Object username = claims.get(ClaimsUtil.CLAIM_KEY_USERNAME);
        Object roles = claims.get(ClaimsUtil.CLAIM_KEY_ROLE);
        Assert.notNull(userId,"no user id found in jwt !");
        Assert.notNull(username,"no username found in jwt !");
        Assert.notNull(roles,"no roles info found in jwt !");
        context.addZuulRequestHeader(ClaimsUtil.CLAIM_KEY_USER_ID,userId.toString());
        context.addZuulRequestHeader(ClaimsUtil.CLAIM_KEY_USERNAME,username.toString());
        context.addZuulRequestHeader(ClaimsUtil.CLAIM_KEY_ROLE,roles.toString());
        return context;
    }

}
